package com.mine.springmvc.run;

import java.util.concurrent.locks.ReentrantLock;

/*
* 通过实现Runnable接口实现一个线程类
*
* 实现Runnable接口具有多线程能力
* 启动线程： 传入目标对象+ thread对象.start()
*
* 推荐使用：避免单继承的局限性，灵活方便，方便同一个对象被多个线程使用
*
* 一份资源
*
* 多个代理
*
* runnable 接口其实是一种静态代理模式
*
* 多个线程操作同一个资源，会出现线程安全问题，例如下面的人拿到了同一张票
*
* sleep 可以让线程休眠，但此时不会释放对象锁
* sleep 可以用来模拟延迟、打印倒计时、打印时间
* join 线程插队，插队的线程执行，其他线程阻塞
*
* */
public class UnsafeBuyTicket implements Runnable {

    private int tickets = 10;
    boolean flag = true;

    private ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {

        while (flag){

            //模拟延迟
            try {
                lock.lock();
                buy();
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        }

    }

    /*
    * 这个方法是不安全的
    * synchronized 关键词 保障同时只有一个线程去操作
    * synchronized 关键字 作用于方法 或者代码块
    * synchronized 可以解决线程安全问题
    *
    * private synchronized  void buy(){....}
    *
    * 嵌套使用synchronized 代码块 会出现死锁的情况
    *
    * lock锁 ReentrantLock
    *
    * */
    private   void buy(){

        if(tickets<=0){
            flag = false;
            return;
        }
        System.out.println(Thread.currentThread().getName()+"-->买到了第"+tickets--+"张票");

    }


    public static void main(String[] args) {

        UnsafeBuyTicket testThread2 = new UnsafeBuyTicket();
        // 多个线程，一份资源
        new Thread(testThread2,"小明").start();
        new Thread(testThread2,"老师").start();
        new Thread(testThread2,"黄牛").start();


    }



}
